package com.cy.dda.comm.config;

import com.cy.dda.comm.constant.CacheConstants;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * redis 配置
 *
 * @author: tanyilin
 * @create: 2018年10月26日 下午6:30:30
 */
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
@EnableConfigurationProperties(CacheProperties.class)
public class RedisConfig extends CachingConfigurerSupport{

	@Autowired
	private CacheProperties cacheProperties;
	@Value("${spring.application.name}")
	private String appName;
	
	@Bean
	@ConditionalOnMissingBean(name = "redisTemplate")
	public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
		RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
		Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new
                Jackson2JsonRedisSerializer<>(Object.class);
		ObjectMapper om = new ObjectMapper();
		om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);// 跳过空值字段
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
	}
	
	@Bean
	public RedisCacheManager redisCacheManager(RedisTemplate<Object, Object> redisTemplate) {
		RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
		cacheManager.setUsePrefix(true);
		//设置不同的cache的name不同的过期时间
        Map<String, Long> expires = new HashMap<>();
        expires.put(CacheConstants.CACHE_VALUE_15S, 15L);
        expires.put(CacheConstants.CACHE_VALUE_1M, 60L);
        expires.put(CacheConstants.CACHE_VALUE_2M, 2 * 60L);
        expires.put(CacheConstants.CACHE_VALUE_1H, 60 * 60L);
        expires.put(CacheConstants.CACHE_VALUE_2H, 2 * 60 * 60L);
        expires.put(CacheConstants.CACHE_RULE_ROLE, 24 * 60 * 60L);
        expires.put(CacheConstants.CACHE_VALUE_24H, 24 * 60 * 60L);
        cacheManager.setExpires(expires);
        List<String> cacheNames = cacheProperties.getCacheNames();
        if (!cacheNames.isEmpty()) {
            cacheManager.setCacheNames(cacheNames);
        }
        return cacheManager;
	}
	
	@Override
	public KeyGenerator keyGenerator() {
		return new KeyGenerator() {
			@Override
			public Object generate(Object target, Method method, Object... params) {
				StringBuilder stringBuilder = new StringBuilder(appName);
				stringBuilder.append(target.getClass().getName());
                stringBuilder.append("-");
                stringBuilder.append(method.getName());
                if (params == null) {
                    return stringBuilder.toString();
                }
                for (Object object : params) {
                    if (params == null) {
                        continue;
                    }
                    stringBuilder.append("-");
                    stringBuilder.append(object.toString());
                }
                return stringBuilder.toString();
			}
		};
	}
	
}
